# 关于pygame sprite精灵的用法
# 0、安装pygame(使用pip模块下载并安装)
# $ python -m pip install --user pygame


# 1、碰撞检测
# https://blog.csdn.net/qq_35456045/article/details/104065682
import pygame
import sys
import random
from pygame.sprite import Sprite


class Ship(Sprite):
    """飞船"""
    def __init__(self, ai_game):
        """初始化飞船并设置其初始位置"""
        super().__init__()
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()

        # 加载飞船图像及获取外接矩形
        self.image = pygame.image.load(
            'PythonPrograming/basic/images/ship.bmp')
        self.rect = self.image.get_rect()

        self.rect.x = random.randint(0, 1200)
        self.rect.y = random.randint(0, 800)

        self.x = float(self.rect.x)
        self.speed = 1
        self.direction_y = 1
        self.direction_x = 1

    def update(self):
        """移动"""
        if self.rect.y < 0 or self.rect.y > 800:
            self.direction_y = -self.direction_y
        self.rect.y -= self.speed * self.direction_y
        if self.rect.x < 0 or self.rect.x > 1200:
            self.direction_x = -self.direction_x
        self.x += self.speed * self.direction_x
        self.rect.x = self.x


class Alien(Sprite):
    """外星人类"""
    def __init__(self, ai_game):
        """初始化外星人并设置位置"""
        super().__init__()
        self.screen = ai_game.screen
        # 加载外星人图片，设置rect
        self.image = pygame.image.load(
            "PythonPrograming/basic/images/alien.bmp")
        self.rect = self.image.get_rect()

        self.rect.x = random.randint(0, 1200)
        self.rect.y = random.randint(0, 800)

        self.x = float(self.rect.x)
        self.speed = 2
        self.direction_y = 1
        self.direction_x = 1

    def update(self):
        """移动"""
        if self.rect.y < 0 or self.rect.y > 800:
            self.direction_y = -self.direction_y
        self.rect.y += self.speed * self.direction_y
        if self.rect.x < 0 or self.rect.x > 1200:
            self.direction_x = -self.direction_x
        self.x += self.speed * self.direction_x
        self.rect.x = self.x


class Game:
    """主画面"""
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((1200, 800))
        self.ships = pygame.sprite.Group()
        self.aliens = pygame.sprite.Group()
        count = 20
        while count > 0:
            count -= 1
            self.ship = Ship(self)
            self.alien = Alien(self)
            self.ships.add(self.ship)
            self.aliens.add(self.alien)

    def run_game(self):
        """开始游戏主循环"""
        while True:
            # 游戏必须监测键盘鼠标事件，否则会陷入无法响应的死循环
            self._check_event()
            self.ships.update()
            self.aliens.update()
            self._update_screen()

    def _check_event(self):
        """监视键盘和鼠标事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            # elif event.type == pygame.KEYUP:
            #     self._check_keyup_events(event)

    def _check_keydown_events(self, event):
        """响应按键"""
        if event.key == pygame.K_q:
            sys.exit()

    def _update_screen(self):
        """绘制屏幕"""
        self.screen.fill((255, 255, 255))
        self.ships.draw(self.screen)
        self.aliens.draw(self.screen)
        # 碰撞测试
        # 每次画面更新检测是否重叠
        # groupcollide(group1, group2, dokill1, dokill2)
        # dokill为True的组，碰撞后消失
        pygame.sprite.groupcollide(self.ships, self.aliens, True, True)
        # 让最近绘制的屏幕可见
        pygame.display.flip()


if __name__ == '__main__':
    Game().run_game()

# 01. 了解碰撞检测方法
# pygame 提供了 两个非常方便 的方法可以实现碰撞检测：

# pygame.sprite.groupcollide()
# 两个精灵组 中 所有的精灵 的碰撞检测
# groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
#   如果将 dokill 设置为 True，则 发生碰撞的精灵将被自动移除
#   collided 参数是用于 计算碰撞的回调函数
#       如果没有指定，则每个精灵必须有一个 rect 属性

# pygame.sprite.spritecollide()
# 判断 某个精灵 和 指定精灵组 中的精灵的碰撞
# spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
#   如果将 dokill 设置为 True，则 指定精灵组 中 发生碰撞的精灵将被自动移除
#   collided 参数是用于 计算碰撞的回调函数
#       如果没有指定，则每个精灵必须有一个 rect 属性
#   返回 精灵组 中跟 精灵 发生碰撞的 精灵列表
